home *** CD-ROM | disk | FTP | other *** search
/ PLAYymate for OS/2 / Playmate for OS2.iso / p4os2008 / ckrstrat.c < prev    next >
C/C++ Source or Header  |  1990-09-01  |  25KB  |  754 lines

  1. /*----------------------------------------------------------------------
  2.    CKRSTRAT.C -- Determines best move from board position, Version 0.40
  3.                  (c) 1990, Charles Petzold
  4.   ----------------------------------------------------------------------*/
  5.  
  6. #define INCL_WIN
  7. #include <os2.h>
  8. #include <process.h>
  9. #include <stdlib.h>
  10. #include "checkers.h"
  11. #include "ckrstrat.h"
  12. #include "ckrmoves.h"
  13.  
  14. #define USE_MALLOC  TRUE
  15.  
  16. typedef struct
  17.      {
  18.      MOVE  *pmove ;
  19.      SHORT sLevel ;
  20.      HWND  hwndJudge ;
  21.      }
  22.      THREADPARAMS ;
  23.  
  24. extern HAB hab ;
  25.  
  26. HWND hwndClient ;
  27.  
  28.      /*--------------------------------------------------------
  29.         CksAllocateMem:  Allocate or reallocate a memory block
  30.        --------------------------------------------------------*/
  31.  
  32. static VOID * CksAllocateMem (VOID * pIn, size_t iSize)
  33.      {
  34.      VOID * p ;
  35.  
  36. #if USE_MALLOC
  37.  
  38.      p = realloc (pIn, iSize) ;
  39.  
  40. #else
  41.  
  42.      {
  43.      SEL sel ;
  44.  
  45.      if (pIn == NULL)
  46.           {
  47.           if (DosAllocSeg ((USHORT) iSize, &sel, SEG_NONSHARED))
  48.                sel = 0 ;
  49.  
  50.           p = MAKEP (sel, 0) ;
  51.           }
  52.      else
  53.           {
  54.           if (DosReallocSeg ((USHORT) iSize, SELECTOROF (pIn)))
  55.                p = NULL ;
  56.           else
  57.                p = pIn ;
  58.           }
  59.      }
  60.  
  61. #endif
  62.  
  63.      if (p == NULL)
  64.           {
  65.           WinPostMsg (hwndClient, WM_TELL_CLIENT_NO_MEMORY, NULL, NULL) ;
  66.  
  67.           _endthread () ;
  68.           }
  69.  
  70.      return p ;
  71.      }
  72.  
  73.      /*----------------------------------
  74.         CksFreeMem:  Free a memory block
  75.        ----------------------------------*/
  76.  
  77. static VOID CksFreeMem (VOID * p)
  78.      {
  79.  
  80. #if USE_MALLOC
  81.  
  82.      free (p) ;
  83.  
  84. #else
  85.  
  86.      DosFreeSeg (SELECTOROF (p)) ;
  87.  
  88. #endif
  89.  
  90.      }
  91.  
  92.      /*-------------------------------------------------------------
  93.         CksQueryNumBitsInLong:  Returns number of bits set in ULONG
  94.        -------------------------------------------------------------*/
  95.  
  96. static SHORT CksQueryNumBitsInLong (ULONG l)
  97.      {
  98.      SHORT cBits = 0 ;
  99.  
  100.      while (l > 0)
  101.           {
  102.           if (l & 1)
  103.                cBits++ ;
  104.  
  105.           l >>= 1 ;
  106.           }
  107.      return cBits ;
  108.      }
  109.  
  110.      /*------------------------------------------------------------------
  111.         CksQueryOneBitInLong: Returns ULONG with only (n-1)th bit set.
  112.  
  113.         For example, CksQueryOneBitInLong (0x00000305, 0) --> 0x00000001
  114.                                           (0x00000305, 1) --> 0x00000004
  115.                                           (0x00000305, 2) --> 0x00000100
  116.                                           (0x00000305, 3) --> 0x00000200
  117.                                           (0x00000305, 4) --> 0x00000000
  118.        ------------------------------------------------------------------*/
  119.  
  120. static ULONG CksQueryOneBitInLong (ULONG l, SHORT n)
  121.      {
  122.      SHORT iCount = 0, i ;
  123.      ULONG ulMask = 1 ;
  124.  
  125.      for (i = 0 ; i < 32 ; i++)
  126.           {
  127.           if (ulMask & l)
  128.                {
  129.                if (n == iCount)
  130.                     return ulMask ;
  131.                else
  132.                     iCount++ ;
  133.                }
  134.           ulMask <<= 1 ;
  135.           }
  136.      return 0 ;
  137.      }
  138.  
  139.      /*--------------------------------------------------------
  140.         CksQueryBitPosInLong: Obtains position of LSB in ULONG
  141.        --------------------------------------------------------*/
  142.  
  143. static SHORT CksQueryBitPosInLong (ULONG l)
  144.      {
  145.      SHORT i ;
  146.  
  147.      for (i = 0 ; i < 32 ; i++)
  148.           {
  149.           if (l & 1)
  150.                return i ;
  151.  
  152.           l >>= 1 ;
  153.           }
  154.      return -1 ;
  155.      }
  156.  
  157.      /*----------------------------------------------------------
  158.         CksGetMaxValue:  Returns the maximum value from an array
  159.                          (assumes lowest value is -10000)
  160.        ----------------------------------------------------------*/
  161.  
  162. static SHORT CksGetMaxValue (SHORT asValue[], SHORT cValues)
  163.      {
  164.      SHORT i, sMax = -10000 ;
  165.  
  166.      for (i = 0 ; i < cValues ; i++)
  167.           if (asValue[i] > sMax)
  168.                sMax = asValue[i] ;
  169.  
  170.      return sMax ;
  171.      }
  172.  
  173.      /*-----------------------------------------------------------------
  174.         CksGetMaxValueIndex:  Returns the index of a maximum value from
  175.                               an array (randomly if multiple maximums)
  176.        -----------------------------------------------------------------*/
  177.  
  178. static SHORT CksGetMaxValueIndex (SHORT asValue[], SHORT cValues)
  179.      {
  180.      SHORT i, sMax, cSame, iMax, sRand, iIndex ;
  181.  
  182.      sMax  = CksGetMaxValue (asValue, cValues) ;
  183.      cSame = 0 ;
  184.  
  185.      for (i = 0 ; i < cValues ; i++)
  186.           if (asValue[i] == sMax)
  187.                {
  188.                iMax = i ;
  189.                cSame ++ ;
  190.                }
  191.  
  192.      if (cSame == 1)
  193.           return iMax ;
  194.  
  195.      sRand  = rand () % cSame ;
  196.      iIndex = 0 ;
  197.  
  198.      for (i = 0 ; i < cValues ; i++)
  199.           if (asValue[i] == sMax)
  200.                {
  201.                if (iIndex == sRand)
  202.                     {
  203.                     iMax = i ;
  204.                     break ;
  205.                     }
  206.                else
  207.                     iIndex ++ ;
  208.                }
  209.  
  210.      return iMax ;
  211.      }
  212.  
  213.      /*------------------------------------------------------------------
  214.         CksApplyChangesToBoard:  Modifies next BOARD structure in a MOVE
  215.                                  structure based on a submove
  216.        ------------------------------------------------------------------*/
  217.  
  218. static VOID CksApplyChangesToBoard (MOVE *pmove)
  219.      {
  220.      SHORT i = pmove->cSubMoves - 1 ;
  221.  
  222.      pmove->asubmove[i+1].brd = pmove->asubmove[i].brd ;
  223.  
  224.      if (pmove->sColor == BLACK)
  225.           {
  226.           pmove->asubmove[i+1].brd.ulBlack &= ~(1L << pmove->asubmove[i].iBeg) ;
  227.           pmove->asubmove[i+1].brd.ulBlack |=  (1L << pmove->asubmove[i].iEnd) ;
  228.           }
  229.      else
  230.           {
  231.           pmove->asubmove[i+1].brd.ulWhite &= ~(1L << pmove->asubmove[i].iBeg) ;
  232.           pmove->asubmove[i+1].brd.ulWhite |=  (1L << pmove->asubmove[i].iEnd) ;
  233.           }
  234.  
  235.      if (pmove->asubmove[i].brd.ulKing & (1L << pmove->asubmove[i].iBeg))
  236.           {
  237.           pmove->asubmove[i+1].brd.ulKing  &= ~(1L << pmove->asubmove[i].iBeg) ;
  238.           pmove->asubmove[i+1].brd.ulKing  |=  (1L << pmove->asubmove[i].iEnd) ;
  239.           }
  240.  
  241.      if (pmove->asubmove[i].iJmp != -1)
  242.           {
  243.           pmove->asubmove[i+1].brd.ulBlack &= ~(1L << pmove->asubmove[i].iJmp) ;
  244.           pmove->asubmove[i+1].brd.ulWhite &= ~(1L << pmove->asubmove[i].iJmp) ;
  245.           pmove->asubmove[i+1].brd.ulKing  &= ~(1L << pmove->asubmove[i].iJmp) ;
  246.           }
  247.  
  248.      if (pmove->asubmove[i+1].brd.ulKing & (1L << pmove->asubmove[i].iEnd))
  249.           pmove->sKing = 1 ;
  250.  
  251.      else if ((pmove->sColor == BLACK && pmove->asubmove[i].iEnd > 27) ||
  252.               (pmove->sColor == WHITE && pmove->asubmove[i].iEnd <  4))
  253.           {
  254.           pmove->fNewKing = TRUE ;
  255.           pmove->asubmove[i+1].brd.ulKing |= (1L << pmove->asubmove[i].iEnd) ;
  256.           }
  257.      }
  258.  
  259.      /*---------------------------------------------------------------------
  260.         CksGetAllJumps:  Recursive routine to fill MOVEBLOCK structure with
  261.                          all possible jumps.
  262.        ---------------------------------------------------------------------*/
  263.  
  264. static VOID CksGetAllJumps (MOVEBLOCK *pmoveblk, BOARD brdIn, SHORT sColor,
  265.                             ULONG ulJumpIn, SHORT sSubMove)
  266.      {
  267.      BOARD brd ;
  268.      SHORT i, iBeg, iEnd, iJmp,
  269.             cJumps,  sJump,  cDests,  sDest ;
  270.      ULONG ulJumps, ulJump, ulDests, ulDest ;
  271.  
  272.      ulDests = CkmQueryJumpDestinations (&brdIn, sColor, ulJumpIn) ;
  273.      cDests  = CksQueryNumBitsInLong (ulDests) ;
  274.  
  275.      for (sDest = 0 ; sDest < cDests ; sDest++)
  276.           {
  277.           ulDest = CksQueryOneBitInLong (ulDests, sDest) ;
  278.           iBeg   = CksQueryBitPosInLong (ulJumpIn) ;
  279.           iEnd   = CksQueryBitPosInLong (ulDest) ;
  280.           iJmp   = CkmQueryJumpedPiece (iBeg, iEnd) ;
  281.  
  282.                     // Reallocate MOVEBLOCK structure for this move
  283.  
  284.           i = pmoveblk->cMoves ;
  285.  
  286.           pmoveblk = CksAllocateMem (pmoveblk, sizeof (MOVEBLOCK) +
  287.                                                sizeof (MOVEP) * i) ;
  288.  
  289.                     // Copy the MOVEP structure from previous move
  290.  
  291.           if (sSubMove > 0 && sDest > 0)
  292.                pmoveblk->amovep[i] = pmoveblk->amovep[i - 1] ;
  293.  
  294.           pmoveblk->amovep[i].sColor                  = sColor ;
  295.           pmoveblk->amovep[i].sKing                   = 0 ;
  296.           pmoveblk->amovep[i].cSubMoves               = sSubMove + 1 ;
  297.           pmoveblk->amovep[i].fNewKing                = FALSE ;
  298.           pmoveblk->amovep[i].asubmove[sSubMove].brd  = brdIn ;
  299.           pmoveblk->amovep[i].asubmove[sSubMove].iBeg = iBeg ;
  300.           pmoveblk->amovep[i].asubmove[sSubMove].iEnd = iEnd ;
  301.           pmoveblk->amovep[i].asubmove[sSubMove].iJmp = iJmp ;
  302.           pmoveblk->amovep[i].pmoveblk                = NULL ;
  303.  
  304.           CksApplyChangesToBoard ((MOVE *) &pmoveblk->amovep[i]) ;
  305.  
  306.           brd     = pmoveblk->amovep[i].asubmove[sSubMove + 1].brd ;
  307.           ulJumps = ulDest & CkmQueryAllJumpablePieces (&brd, sColor) ;
  308.  
  309.           if (ulJumps > 0 && pmoveblk->amovep[i].fNewKing == FALSE)
  310.                {
  311.                cJumps = CksQueryNumBitsInLong (ulJumps) ;
  312.  
  313.                for (sJump = 0 ; sJump < cJumps ; sJump++)
  314.                     {
  315.                     ulJump = CksQueryOneBitInLong (ulJumps, sJump) ;
  316.  
  317.                     CksGetAllJumps (pmoveblk, brd, sColor,
  318.                                     ulJump, sSubMove + 1) ;
  319.                     }
  320.                }
  321.  
  322.           if (sSubMove == 0 || sDest < cDests - 1)
  323.                pmoveblk->cMoves ++ ;
  324.           }
  325.      }
  326.  
  327.      /*--------------------------------------------------------------------
  328.         CksGetAllPossibleMoves:  Allocates a MOVEBLOCK structure and fills
  329.                                  it in with all possible moves.
  330.        --------------------------------------------------------------------*/
  331.  
  332. static MOVEBLOCK * CksGetAllPossibleMoves (BOARD brd, SHORT sColor)
  333.      {
  334.      MOVEBLOCK *pmoveblk ;
  335.      SHORT     i, iBeg, iEnd,
  336.                 cMoves,  cJumps,  sMove,  sJump,  cDests,  sDest ;
  337.      ULONG     ulMoves, ulJumps, ulMove, ulJump, ulDests, ulDest ;
  338.  
  339.                // Allocate MOVEBLOCK structure and initialize one move
  340.                // to indicate a "NULL" move
  341.  
  342.      pmoveblk = CksAllocateMem (NULL, sizeof (MOVEBLOCK)) ;
  343.      pmoveblk->cMoves = 0 ;
  344.      pmoveblk->amovep[0].sColor           = sColor ;
  345.      pmoveblk->amovep[0].sKing            = 0 ;
  346.      pmoveblk->amovep[0].cSubMoves        = 0 ;
  347.      pmoveblk->amovep[0].fNewKing         = FALSE ;
  348.      pmoveblk->amovep[0].asubmove[0].brd  = brd ;
  349.      pmoveblk->amovep[0].pmoveblk         = NULL ;
  350.  
  351.                // Find all pieces that can make moves and jumps
  352.  
  353.      ulMoves = CkmQueryAllMoveablePieces (&brd, sColor) ;
  354.      ulJumps = CkmQueryAllJumpablePieces (&brd, sColor) ;
  355.  
  356.                // Do the following for a move but not a jump
  357.  
  358.      if (ulMoves > 0 && ulJumps == 0)
  359.           {
  360.           cMoves = CksQueryNumBitsInLong (ulMoves) ;
  361.  
  362.           for (sMove = 0 ; sMove < cMoves ; sMove++)
  363.                {
  364.                ulMove  = CksQueryOneBitInLong (ulMoves, sMove) ;
  365.                ulDests = CkmQueryMoveDestinations (&brd, sColor, ulMove) ;
  366.                cDests  = CksQueryNumBitsInLong (ulDests) ;
  367.  
  368.                for (sDest = 0 ; sDest < cDests ; sDest++)
  369.                     {
  370.                     ulDest = CksQueryOneBitInLong (ulDests, sDest) ;
  371.                     iBeg   = CksQueryBitPosInLong (ulMove) ;
  372.                     iEnd   = CksQueryBitPosInLong (ulDest) ;
  373.  
  374.                               // Reallocate the MOVEBLOCK structure
  375.  
  376.                     i = pmoveblk->cMoves ;
  377.  
  378.                     pmoveblk->cMoves ++ ;
  379.  
  380.                     pmoveblk = CksAllocateMem (pmoveblk, sizeof (MOVEBLOCK) +
  381.                                                          sizeof (MOVEP) * i) ;
  382.  
  383.                               // Fill in the information for this move
  384.  
  385.                     pmoveblk->amovep[i].sColor           = sColor ;
  386.                     pmoveblk->amovep[i].sKing            = 0 ;
  387.                     pmoveblk->amovep[i].cSubMoves        = 1 ;
  388.                     pmoveblk->amovep[i].fNewKing         = FALSE ;
  389.                     pmoveblk->amovep[i].asubmove[0].brd  = brd ;
  390.                     pmoveblk->amovep[i].asubmove[0].iBeg = iBeg ;
  391.                     pmoveblk->amovep[i].asubmove[0].iEnd = iEnd ;
  392.                     pmoveblk->amovep[i].asubmove[0].iJmp = -1 ;
  393.                     pmoveblk->amovep[i].pmoveblk         = NULL ;
  394.  
  395.                               // Apply the changes to the next asubmove BOARD
  396.  
  397.                     CksApplyChangesToBoard ((MOVE *) &pmoveblk->amovep[i]) ;
  398.                     }
  399.                }
  400.           }
  401.  
  402.      else if (ulJumps > 0)
  403.           {
  404.           cJumps = CksQueryNumBitsInLong (ulJumps) ;
  405.  
  406.           for (sJump = 0 ; sJump < cJumps ; sJump++)
  407.                {
  408.                ulJump = CksQueryOneBitInLong (ulJumps, sJump) ;
  409.  
  410.                CksGetAllJumps (pmoveblk, brd, sColor, ulJump, 0) ;
  411.                }
  412.           }
  413.  
  414.      return pmoveblk ;
  415.      }
  416.  
  417.      /*-----------------------------------------------------------
  418.         CksCalculateAdvantage:  Total the pieces, weighting kings
  419.                                 75% higher than non-kings.
  420.        -----------------------------------------------------------*/
  421.  
  422. static SHORT CksCalculateAdvantage (BOARD *pbrd, SHORT sColor)
  423.      {
  424.      SHORT sAdvantage ;
  425.      ULONG B = pbrd->ulBlack,
  426.            W = pbrd->ulWhite,
  427.            K = pbrd->ulKing ;
  428.  
  429.      if (W == 0)
  430.           sAdvantage = 10000 ;
  431.  
  432.      else if (B == 0)
  433.           sAdvantage = -10000 ;
  434.  
  435.      else if (CkmQueryAllMoveablePieces (pbrd, WHITE) == 0L &&
  436.               CkmQueryAllJumpablePieces (pbrd, WHITE) == 0L)
  437.  
  438.           sAdvantage = 10000 ;
  439.  
  440.      else if (CkmQueryAllMoveablePieces (pbrd, BLACK) == 0L &&
  441.               CkmQueryAllJumpablePieces (pbrd, BLACK) == 0L)
  442.  
  443.           sAdvantage = -10000 ;
  444.  
  445.      else
  446.           sAdvantage = (100 * CksQueryNumBitsInLong (B & ~K) +
  447.                         175 * CksQueryNumBitsInLong (B &  K)) -
  448.                        (100 * CksQueryNumBitsInLong (W & ~K) +
  449.                         175 * CksQueryNumBitsInLong (W &  K)) ;
  450.  
  451.      return (sColor == BLACK ? sAdvantage : -sAdvantage) ;
  452.      }
  453.  
  454.      /*--------------------------------------------------------------
  455.         CksGetBestAdvantage:  Loop through possible moves and return
  456.                               index of best move (if fIndex is TRUE)
  457.                               or the value of the best move (FALSE)
  458.        --------------------------------------------------------------*/
  459.  
  460. static SHORT CksGetBestAdvantage (MOVEBLOCK *pmoveblk, SHORT sColor,
  461.                                                        BOOL fIndex)
  462.      {
  463.      BOARD brd ;
  464.      SHORT i, cMoves, cSubMoves, sReturn ;
  465.      SHORT *asValue ;
  466.  
  467.           // Get the number of moves in the MOVEBLOCK
  468.  
  469.      cMoves = pmoveblk->cMoves ;
  470.  
  471.           // If 0 or 1 move, and returning index, return 0
  472.  
  473.      if (fIndex && cMoves <= 1)
  474.           return 0 ;
  475.  
  476.           // If 0 moves, and returning value, return -10000 ;
  477.  
  478.      if (!fIndex && cMoves == 0)
  479.           return -10000 ;
  480.  
  481.           // Else allocate memory for number of moves
  482.  
  483.      asValue = CksAllocateMem (NULL, sizeof (SHORT) * cMoves) ;
  484.  
  485.           // Loop through the moves, calculating advantages
  486.  
  487.      for (i = 0 ; i < cMoves ; i++)
  488.           {
  489.           cSubMoves  = pmoveblk->amovep[i].cSubMoves ;
  490.           brd        = pmoveblk->amovep[i].asubmove[cSubMoves].brd ;
  491.           asValue[i] = CksCalculateAdvantage (&brd, sColor) ;
  492.           }
  493.  
  494.           // Determine what to return from fIndex parameter
  495.  
  496.      if (fIndex)
  497.           sReturn = CksGetMaxValueIndex (asValue, cMoves) ;
  498.      else
  499.           sReturn = CksGetMaxValue (asValue, cMoves) ;
  500.  
  501.      CksFreeMem (asValue) ;
  502.  
  503.      return sReturn ;
  504.      }
  505.  
  506.      /*---------------------------------------------------------------------
  507.         CksFreeMoveBlock:  Free MOVEBLOCK structure and all other MOVEBLOCK
  508.                            structures in tree.
  509.        ---------------------------------------------------------------------*/
  510.  
  511. static VOID CksFreeMoveBlock (MOVEBLOCK *pmoveblk)
  512.      {
  513.      SHORT i ;
  514.  
  515.      for (i = 0 ; i < pmoveblk->cMoves ; i++)
  516.           {
  517.           if (pmoveblk->amovep[i].pmoveblk != NULL)
  518.                CksFreeMoveBlock (pmoveblk->amovep[i].pmoveblk) ;
  519.           }
  520.  
  521.      CksFreeMem (pmoveblk) ;
  522.      }
  523.  
  524.      /*-----------------------------------------------------------------
  525.         CksGetCounterMoves:  Recursively get counter-moves depending on
  526.                              sLevel setting.
  527.        -----------------------------------------------------------------*/
  528.  
  529. static VOID CksGetCounterMoves (MOVEBLOCK *pmoveblk, SHORT sLevel)
  530.      {
  531.      BOARD     brd ;
  532.      MOVEBLOCK *pmoveblk2 ;
  533.      SHORT     i, cSubMoves, sColor ;
  534.  
  535.                // If sLevel is 0 or less, just return
  536.  
  537.      if (sLevel <= 0)
  538.           return ;
  539.  
  540.                // If no moves on previous level, set the counter move to NULL
  541.  
  542.      if (pmoveblk->cMoves == 0)
  543.           {
  544.           pmoveblk2 = CksAllocateMem (NULL, sizeof (MOVEBLOCK)) ;
  545.           *pmoveblk2 = *pmoveblk ;
  546.           pmoveblk->amovep[0].pmoveblk = pmoveblk2 ;
  547.  
  548.           CksGetCounterMoves (pmoveblk2, sLevel - 1) ;
  549.           }
  550.  
  551.                // Otherwise, loop through all the moves and get counter moves
  552.  
  553.      for (i = 0 ; i < pmoveblk->cMoves ; i++)
  554.           {
  555.           cSubMoves = pmoveblk->amovep[i].cSubMoves ;
  556.           brd       = pmoveblk->amovep[i].asubmove[cSubMoves].brd ;
  557.           sColor    = pmoveblk->amovep[i].sColor ^ 1 ;
  558.  
  559.           pmoveblk->amovep[i].pmoveblk = CksGetAllPossibleMoves (brd, sColor) ;
  560.  
  561.           CksGetCounterMoves (pmoveblk->amovep[i].pmoveblk, sLevel - 1) ;
  562.           }
  563.      }
  564.  
  565.      /*------------------------------------------------------
  566.         CksStrategyThread:  Thread for determining best move
  567.        ------------------------------------------------------*/
  568.  
  569. static VOID CksStrategyThread (THREADPARAMS *ptp)
  570.      {
  571.      BOARD     brd ;
  572.      HWND      hwndJudge ;
  573.      MOVE      *pmove ;
  574.      MOVEBLOCK *pmoveblkMain,
  575.                *pmoveblk ;
  576.      SHORT     sLevel, i, sColor, cMoves, iAdv ;
  577.      SHORT     *asValue ;
  578.  
  579.                // Save fields of THREADPARAMS structure
  580.  
  581.      pmove     = ptp->pmove ;
  582.      sLevel    = ptp->sLevel ;
  583.      hwndJudge = ptp->hwndJudge ;
  584.  
  585.                // Set random number generator
  586.  
  587.      srand ((int) WinGetCurrentTime (hab)) ;
  588.  
  589.                // Get the initial board layout and the color
  590.  
  591.      brd    = pmove->asubmove[0].brd ;
  592.      sColor = pmove->sColor ;
  593.  
  594.                // Determine all possible moves & initial number of moves
  595.  
  596.      pmoveblkMain = CksGetAllPossibleMoves (brd, sColor) ;
  597.  
  598.      cMoves = pmoveblkMain->cMoves ;
  599.  
  600.                // If only 0 or 1 possible moves, nothing much to do
  601.  
  602.      if (cMoves <= 1)
  603.           {
  604.           iAdv = 0 ;
  605.           }
  606.  
  607.                // For Simple Level, make random (but legal) move
  608.  
  609.      else if (sLevel == LEVEL_SIMPLE)
  610.           {
  611.           iAdv = rand () % cMoves ;
  612.           }
  613.  
  614.                // For Beginner Level, make best immediate move
  615.  
  616.      else if (sLevel == LEVEL_BEGINNER)
  617.           {
  618.           iAdv = CksGetBestAdvantage (pmoveblkMain, sColor, TRUE) ;
  619.           }
  620.  
  621.                // For Intermediate Level, choose best move for best response
  622.  
  623.      else if (sLevel == LEVEL_INTERMEDIATE)
  624.           {
  625.           CksGetCounterMoves (pmoveblkMain, 2) ;
  626.  
  627.           asValue = CksAllocateMem (NULL, cMoves * sizeof (SHORT)) ;
  628.  
  629.           for (i = 0 ; i < cMoves ; i++)
  630.                {
  631.                pmoveblk   = pmoveblkMain->amovep[i].pmoveblk ;
  632.                iAdv       = CksGetBestAdvantage (pmoveblk, sColor ^ 1, TRUE) ;
  633.                pmoveblk   = pmoveblk->amovep[iAdv].pmoveblk ;
  634.                asValue[i] = CksGetBestAdvantage (pmoveblk, sColor, FALSE) ;
  635.                }
  636.  
  637.           iAdv = CksGetMaxValueIndex (asValue, cMoves) ;
  638.  
  639.           CksFreeMem (asValue) ;
  640.           }
  641.  
  642.                // For Advanced Level, go 5 levels deep
  643.  
  644.      else if (sLevel == LEVEL_ADVANCED)
  645.           {
  646.           MOVEBLOCK *pmoveblk1, *pmoveblk2, *pmoveblk3, *pmoveblk4 ;
  647.           SHORT     i1, i2, i3 ;
  648.           SHORT     *asValue2, *asValue3 ;
  649.  
  650.           CksGetCounterMoves (pmoveblkMain, 4) ;
  651.  
  652.           asValue = CksAllocateMem (NULL, cMoves * sizeof (SHORT)) ;
  653.  
  654.           for (i1 = 0 ; i1 < cMoves ; i1++)
  655.                {
  656.                asValue2 = NULL ;
  657.                asValue3 = NULL ;
  658.                i        = 0 ;
  659.  
  660.                pmoveblk1 = pmoveblkMain->amovep[i1].pmoveblk ;
  661.  
  662.                for (i2 = 0 ; i2 < max (1, pmoveblk1->cMoves) ; i2++)
  663.                     {
  664.                     pmoveblk2 = pmoveblk1->amovep[i2].pmoveblk ;
  665.  
  666.                     for (i3 = 0 ; i3 < max (1, pmoveblk2->cMoves) ; i3++)
  667.                          {
  668.                          pmoveblk3 = pmoveblk2->amovep[i3].pmoveblk ;
  669.  
  670.                          asValue2 = CksAllocateMem (asValue2,
  671.                                                     (i + pmoveblk3->cMoves) *
  672.                                                     sizeof (SHORT)) ;
  673.  
  674.                          asValue3 = CksAllocateMem (asValue3,
  675.                                                     (i + pmoveblk3->cMoves) *
  676.                                                     sizeof (SHORT)) ;
  677.  
  678.                          asValue2[i] = CksGetBestAdvantage (pmoveblk3,
  679.                                                             sColor ^ 1, FALSE) ;
  680.  
  681.                          iAdv = CksGetBestAdvantage (pmoveblk3,
  682.                                                      sColor ^ 1, TRUE) ;
  683.  
  684.                          pmoveblk4 = pmoveblk3->amovep[iAdv].pmoveblk ;
  685.  
  686.                          asValue3[i] = CksGetBestAdvantage (pmoveblk4,
  687.                                                             sColor, FALSE) ;
  688.                          i++ ;
  689.                          }
  690.                     }
  691.                iAdv = CksGetMaxValueIndex (asValue2, i) ;
  692.  
  693.                asValue[i1] = asValue3[iAdv] ;
  694.  
  695.                CksFreeMem (asValue2) ;
  696.                CksFreeMem (asValue3) ;
  697.                }
  698.  
  699.           iAdv = CksGetMaxValueIndex (asValue, cMoves) ;
  700.  
  701.           CksFreeMem (asValue) ;
  702.           }
  703.  
  704.                // Now get move from iAdv index and free MOVEBLOCK structure
  705.  
  706.      * pmove = * (MOVE *) & pmoveblkMain->amovep[iAdv] ;
  707.  
  708.      CksFreeMoveBlock (pmoveblkMain) ;
  709.  
  710.                // Notify the Judge that the move is ready
  711.  
  712.      WinPostMsg (hwndJudge, WM_TELL_JUDGE_STRAT_MOVE_ENDED,
  713.                  MPFROMP (pmove), NULL) ;
  714.  
  715.      _endthread () ;
  716.      }
  717.  
  718.      /*------------------------------------------------------
  719.         StratWndProc:  Window procedure for strategy routine
  720.        ------------------------------------------------------*/
  721.  
  722. MRESULT EXPENTRY StratWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  723.      {
  724.      static HWND         hwndJudge ;
  725.      static MOVE         *pmove ;
  726.      static SHORT        sLevel ;
  727.      static THREADPARAMS tp ;
  728.      NEWGAME             *pnewgame ;
  729.  
  730.      switch (msg)
  731.           {
  732.           case WM_NEW_GAME:
  733.                pnewgame   = PVOIDFROMMP (mp1) ;
  734.  
  735.                hwndJudge  = pnewgame->hwndJudge ;
  736.                hwndClient = pnewgame->hwndClient ;
  737.                sLevel     = pnewgame->sLevel ;
  738.  
  739.                return 0 ;
  740.  
  741.           case WM_JUDGE_SAYS_MAKE_MOVE:
  742.                pmove = PVOIDFROMMP (mp1) ;
  743.  
  744.                tp.pmove     = pmove ;
  745.                tp.sLevel    = sLevel ;
  746.                tp.hwndJudge = hwndJudge ;
  747.  
  748.                _beginthread (CksStrategyThread, NULL, 8192, &tp) ;
  749.  
  750.                return 0 ;
  751.           }
  752.      return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
  753.      }
  754.